package rtpengine

import (
	"common/rtpengine/rtp"
	"net"
	"time"
)

type SessionRTP struct {
	session
	writeStream *WriteStreamRTP
}

// NewSessionSRTP creates a SRTP session using conn as the underlying transport.
func NewSessionRTP(conn net.Conn, config *Config) (*SessionRTP, error) {
	if config == nil {
		return nil, errNoConfig
	} else if conn == nil {
		return nil, errNoConn
	}

	s := &SessionRTP{
		session: session{
			nextConn:      conn,
			readStreams:   map[uint32]readStream{},
			newStream:     make(chan readStream),
			started:       make(chan interface{}),
			closed:        make(chan interface{}),
			bufferFactory: config.BufferFactory,
		},
	}
	s.writeStream = &WriteStreamRTP{s}
	err := s.session.start(
		s,
	)
	if err != nil {
		return nil, err
	}
	return s, nil
}

// OpenWriteStream returns the global write stream for the Session
func (s *SessionRTP) OpenWriteStream() (*WriteStreamRTP, error) {
	return s.writeStream, nil
}

// OpenReadStream opens a read stream for the given SSRC, it can be used
// if you want a certain SSRC, but don't want to wait for AcceptStream
func (s *SessionRTP) OpenReadStream(ssrc uint32) (*ReadStreamRTP, error) {
	r, _ := s.session.getOrCreateReadStream(ssrc, s, newReadStreamRTP)

	if readStream, ok := r.(*ReadStreamRTP); ok {
		return readStream, nil
	}

	return nil, errFailedTypeAssertion
}

// AcceptStream returns a stream to handle RTP for a single SSRC
func (s *SessionRTP) AcceptStream() (*ReadStreamRTP, uint32, error) {
	stream, ok := <-s.newStream
	if !ok {
		return nil, 0, errStreamAlreadyClosed
	}

	readStream, ok := stream.(*ReadStreamRTP)
	if !ok {
		return nil, 0, errFailedTypeAssertion
	}

	return readStream, stream.GetSSRC(), nil
}

// Close ends the session
func (s *SessionRTP) Close() error {
	return s.session.close()
}

func (s *SessionRTP) write(b []byte) (int, error) {
	packet := &rtp.Packet{}

	err := packet.Unmarshal(b)
	if err != nil {
		return 0, nil
	}

	return s.writeRTP(&packet.Header, packet.Payload)
}

// no encrypt for rtp data.
func (s *SessionRTP) writeRTP(header *rtp.Header, payload []byte) (int, error) {
	if _, ok := <-s.session.started; ok {
		return 0, errStartedChannelUsedIncorrectly
	}

	encrypted, err := header.Marshal()
	if err != nil {
		return 0, err
	}
	encrypted = append(encrypted, payload...)
	return s.session.nextConn.Write(encrypted)
}

func (s *SessionRTP) setWriteDeadline(t time.Time) error {
	return s.session.nextConn.SetWriteDeadline(t)
}

func (s *SessionRTP) setReadDeadline(t time.Time) error {
	return s.session.nextConn.SetReadDeadline(t)
}

// read to buffer directly.
func (s *SessionRTP) decrypt(buf []byte) error {
	h := &rtp.Header{}
	_, err := h.Unmarshal(buf)
	if err != nil {
		return err
	}

	r, isNew := s.session.getOrCreateReadStream(h.SSRC, s, newReadStreamRTP)
	if r == nil {
		return nil // Session has been closed
	} else if isNew {
		s.session.newStream <- r // Notify AcceptStream
	}

	readStream, ok := r.(*ReadStreamRTP)
	if !ok {
		return errFailedTypeAssertion
	}

	//decrypted, err := s.remoteContext.decryptRTP(buf, buf, h, headerLen)
	//if err != nil {
	//	return err
	//}
	_, err = readStream.write(buf)
	if err != nil {
		return err
	}

	return nil
}
